package it.unibo.iss.domotica.edControlling;


import static org.junit.Assert.*;
import it.unibo.iss.domotica.consumptionControlling.ConsumptionControllerFacade;
import it.unibo.iss.domotica.edControlling.EDController;
import it.unibo.iss.domotica.edDomain.Elettrodomestico;
import it.unibo.iss.domotica.edDomain.ImpiantoElettrico;
import it.unibo.iss.domotica.edDomain.StatoED;
import it.unibo.iss.domotica.exceptions.ConsumptionTooHighException;
import it.unibo.iss.domotica.testcommon.TestCommon;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class EDControllerTest extends TestCommon {

	private ConsumptionControllerFacade consumptionController;
	private EDController edController;
	
	@Before
	public void setUp() throws Exception {
		super.setUp();
		
		consumptionController = new ConsumptionControllerFacade(Double.valueOf(prop.getProperty("consumoComplMax")));
		edController = new EDController(consumptionController);
	}
	
	@Test
	public void testAutoPowerOff() {
		String edName1 = "edIB1";
		String edName2 = "edSB0";
		String edName3 = "edSM2";
		String edName4 = "edIA1";
		double consumption1 = 367.0;
		double consumption2 = 456.0;
		double consumption3 = 723.0;	// consume1 + consume2 + consume3 = 1546.0 (threshold max = 3000.0 (properties file))
		double consumption4 = 1600.0;  // consume1 + consume2 + consume3 + consume4 = 3146.0 (threshold max = 3000.0 (properties file))
		
		elettrodomestici.getED(edName1).powerOn();
		elettrodomestici.getED(edName2).powerOn();
		elettrodomestici.getED(edName3).powerOn();
		elettrodomestici.getED(edName4).powerOn();
		
		try {
			elettrodomestici.setConsumptionEd(edName1, consumption1);
			elettrodomestici.setConsumptionEd(edName2, consumption2);
			elettrodomestici.setConsumptionEd(edName3, consumption3);
			elettrodomestici.setConsumptionEd(edName4, consumption4);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		consumptionController.updateConsumption();
		
		if(edController.autoPowerOff() < 0)
			fail();
		else {
			Elettrodomestico ed = (Elettrodomestico) elettrodomestici.getED(edName4);
			assertEquals(StatoED.OFF, ed.getStato());
			
			ed = (Elettrodomestico) elettrodomestici.getED(edName1);
			assertEquals(StatoED.CONDITIONED, ed.getStato());
			
			ed = (Elettrodomestico) elettrodomestici.getED(edName2);
			assertEquals(StatoED.CONDITIONED, ed.getStato());
			
			ed = (Elettrodomestico) elettrodomestici.getED(edName3);
			assertEquals(StatoED.CONDITIONED, ed.getStato());
		}
	}
	
	@Test
	public void testAutoPowerOffWithObserverPattern() {
		String edName1 = "edIB1";
		String edName2 = "edSB0";
		String edName3 = "edSM2";
		String edName4 = "edIA1";
		double consumption1 = 367.0;
		double consumption2 = 456.0;
		double consumption3 = 723.0;	// consume1 + consume2 + consume3 = 1546.0 (threshold max = 3000.0 (properties file))
		double consumption4 = 1600.0;  // consume1 + consume2 + consume3 + consume4 = 3146.0 (threshold max = 3000.0 (properties file))
		
		consumptionController.attach(edController);
		
		elettrodomestici.getED(edName1).powerOn();
		elettrodomestici.getED(edName2).powerOn();
		elettrodomestici.getED(edName3).powerOn();
		elettrodomestici.getED(edName4).powerOn();
		
		try {
			elettrodomestici.setConsumptionEd(edName1, consumption1);
			elettrodomestici.setConsumptionEd(edName2, consumption2);
			elettrodomestici.setConsumptionEd(edName3, consumption3);
			elettrodomestici.setConsumptionEd(edName4, consumption4);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		consumptionController.updateConsumption();
		
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		Elettrodomestico ed = (Elettrodomestico) elettrodomestici.getED(edName4);
		assertEquals(StatoED.OFF, ed.getStato());
		
		ed = (Elettrodomestico) elettrodomestici.getED(edName1);
		assertEquals(StatoED.CONDITIONED, ed.getStato());
		
		ed = (Elettrodomestico) elettrodomestici.getED(edName2);
		assertEquals(StatoED.CONDITIONED, ed.getStato());
		
		ed = (Elettrodomestico) elettrodomestici.getED(edName3);
		assertEquals(StatoED.CONDITIONED, ed.getStato());
	}
	
//	@Test
//	public void testListED() {
//		fail("Not yet implemented");
//	}

	public void testPowerOn() throws ConsumptionTooHighException, Exception {
		String edName1 = "edIB1";
		int res;
		
		try {
			if(edController.powerOn(edName1) < 0) {
				fail();
			}
			else {
				Elettrodomestico ed = (Elettrodomestico) elettrodomestici.getED(edName1);
				assertTrue(ed.getStato() != StatoED.OFF);
			}
		} catch (Exception e) {
			e.printStackTrace();
			fail();
		}
	}
	
	@Test
	public void testPowerOnWithException() {
		String edNameOn = "edSB1"; // consumo min = 1.0, consumo max = 500, media = 250.5
		String edNameNo = "edSM0"; // consumo min = 501, consumo max = 1000, media = 750.5
		String edName1 = "edIB1";
		String edName2 = "edSM0";
		String edName3 = "edSA2";
		double consumption1 = 490.0;
		double consumption2 = 600.0;
		double consumption3 = 1500.0;	// consume1 + consume2 + consume3 = 2590 (threshold max = 3000 (properties file))
		int res;
		boolean thrown = false;
		
		try {
			elettrodomestici.setConsumptionEd(edName1, consumption1);
			elettrodomestici.setConsumptionEd(edName2, consumption2);
			elettrodomestici.setConsumptionEd(edName3, consumption3);
			
			edController.powerOn(edName1);
			edController.powerOn(edName2);
			edController.powerOn(edName3);
		} catch (Exception e) {
			e.printStackTrace();
			fail();
		}
		
		try {
			consumptionController.updateConsumption();

			res = edController.powerOn(edNameOn); // consume1 + consume2 + consume3 + mediumConsumptionEdNameOn = 2840.5 (threshold max = 3000 (properties file))

			if(res < 0) {
				fail();
			}
			else {
				Elettrodomestico ed = (Elettrodomestico) elettrodomestici.getED(edNameOn);
				assertTrue(ed.getStato() != StatoED.OFF);
			}
		}
		catch (Exception e) {
			fail();
		}
		
		try {
			res = edController.powerOn(edNameNo);
			
			if(res < 0) {
				fail();
			}
			else {
				Elettrodomestico ed = (Elettrodomestico) elettrodomestici.getED(edNameNo);
				assertEquals(StatoED.OFF, ed.getStato());
			}
		}
		catch (ConsumptionTooHighException e) {
			thrown = true;
		}
		
		assertTrue(thrown);
	}

	@Test
	public void testPowerOff() throws Exception {
		String edName = "edIB1";
		
		if(edController.powerOn(edName) < 0)
			fail();
		
		Elettrodomestico ed = (Elettrodomestico) elettrodomestici.getED(edName);
		assertTrue(ed.getStato() != StatoED.OFF);
		
		if(edController.powerOff(edName) < 0)
			fail();
		
		assertEquals(StatoED.OFF, ed.getStato());
	}
	
	@Test
	public void testSwitchEdToActive() throws Exception {
		String edName1 = "edIB1";
		String edName2 = "edIM0";
		
		if(edController.powerOn(edName1) < 0)
			fail();
		
		if(edController.powerOn(edName2) < 0)
			fail();
		
		Elettrodomestico ed1 = (Elettrodomestico) elettrodomestici.getED(edName1);
		assertTrue(ed1.getStato() != StatoED.OFF);
		
		Elettrodomestico ed2 = (Elettrodomestico) elettrodomestici.getED(edName2);
		assertTrue(ed2.getStato() != StatoED.OFF);
		
		Thread.sleep(8000);
		
		assertEquals(StatoED.ACTIVE, ed1.getStato());
		assertEquals(StatoED.ACTIVE, ed2.getStato());
	}

//	@Test
//	public void testListEDSuperflui() {
//		fail("Not yet implemented");
//	}

}
